import type {FormActionType, FormProps, FormSchema, UseFormReturnType} from '../types/form';
import type {NamePath} from 'ant-design-vue/lib/form/interface';
import type {DynamicProps} from '@pkg/types';
import {nextTick, onUnmounted, ref, unref, watch} from 'vue';
import {arrayToString, error, getDynamicProps} from '@pkg/utils';
import {request} from '@pkg/request/src';
import {handleRangeValue} from '../utils';

export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;

type Props = Partial<DynamicProps<FormProps>>;

export function useForm(props?: Props): UseFormReturnType {
  const formRef = ref<Nullable<FormActionType>>(null);
  const loadedRef = ref<Nullable<boolean>>(false);
  //主键字段
  const rowKey: any = props?.rowKey;

  async function getForm() {
    const form = unref(formRef);
    if (!form) {
      error('The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!');
    }
    await nextTick();
    return form as FormActionType;
  }

  function register(instance: FormActionType) {
    import.meta.env.PROD &&
    onUnmounted(() => {
      formRef.value = null;
      loadedRef.value = null;
    });
    if (unref(loadedRef) && import.meta.env.PROD && instance === unref(formRef)) return;

    formRef.value = instance;
    loadedRef.value = true;

    watch(
        () => props,
        () => {
          props && instance.setProps(getDynamicProps(props));
        },
        {
          immediate: true,
          deep: true,
        },
    );
  }

  const methods: FormActionType = {
    scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
      const form = await getForm();
      await form.scrollToField(name, options);
    },
    setProps: async (formProps: Partial<FormProps>) => {
      const form = await getForm();
      await form.setProps(formProps);
    },

    updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
      const form = await getForm();
      await form.updateSchema(data);
    },

    resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
      const form = await getForm();
      await form.resetSchema(data);
    },

    clearValidate: async (name?: string | string[]) => {
      const form = await getForm();
      await form.clearValidate(name);
    },

    resetFields: async () => {
      getForm().then(async (form) => {
        await form.resetFields();
      });
    },

    removeSchemaByFiled: async (field: string | string[]) => {
      unref(formRef)?.removeSchemaByFiled(field);
    },

    // TODO promisify
    getFieldsValue: <T>() => {
      return unref(formRef)?.getFieldsValue() as T;
    },

    setFieldsValue: async <T>(values: T) => {
      const form = await getForm();
      await form.setFieldsValue<T>(values);
    },
    /**
     * 提交表单
     * @param options emit 回调事件 values 不传递时自动获取
     */
    formSubmit: async (options?: any) => {
      options.setDrawerProps && options.setDrawerProps({confirmLoading: true});
      if (!rowKey) {
        console.error('未配置rowKey,需在useForm中指定rowKey参数,rowKey为实体类主键字段名');
        return;
      }
      let formData: any;
      try {
        formData = options.values ? options.values : await methods.validate();
      } catch (e) {
        options.setDrawerProps && options.setDrawerProps({confirmLoading: false});
        options.fail && options.fail();
      }
      console.info('表单提交参数:', formData);
      const id = formData[rowKey];
      const handlerName = id ? props?.updateHandler : props?.saveHandler;
      const params = props?.params;
      const url: any = id ? props?.updateApi : props?.saveApi;
      if (handlerName) {
        formData['handlerName'] = handlerName;
      }
      if (params) {
        formData = Object.assign({}, formData, params);
      }
      console.info('id:', id);
      console.info('表单提交参数:', formData);
      return request.post({url: url, params: formData}).then((data) => {
        console.info("表单提交结果:", data)
        //prettier-ignore
        options.emit && options.emit('success', {
          isUpdate: id ? true : false,
          values: formData,
        });
        options.closeDrawer && options.closeDrawer();
      }).catch((e) => {
        console.info("表单提交异常:", e)
        options.fail && options.fail();
      });
    },
    /**
     * 保存或者更新表单
     * @param emit 回调事件
     * @param values 不传递时自动获取
     */
    saveOrUpdate: async <T>(emit?: any, values?: T) => {
      await methods.formSubmit({
        values,
        emit
      })
    },

    appendSchemaByField: async (schema: FormSchema, prefixField: string | undefined, first: boolean) => {
      const form = await getForm();
      await form.appendSchemaByField(schema, prefixField, first);
    },

    submit: async (): Promise<any> => {
      const form = await getForm();
      return form.submit();
    },

    validate: async (nameList?: NamePath[]): Promise<Recordable> => {
      const form: any = await getForm();
      const getProps = props || form.getProps;
      const values = form.validate(nameList).then((values) => {
        for (const key in values) {
          console.info("key",key)
          if (values[key] instanceof Array) {
            const allowToString = arrayToString(getProps, key);
            if (allowToString) {
              values[key] = values[key].join(',');
            }
          }
          if(values[key]==undefined){
            values[key]=''
          }
        }
        console.info("values",values)
        return handleRangeValue(getProps, values);
      });
      return values;
    },

    validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
      const form: any = await getForm();
      return form.validateFields(nameList);
    },
  };

  return [register, methods];
}
